unit SmallStruct.Tools;

interface

uses
  Types,
  Classes,
  SmallStruct.Core,
  SmallStruct.Core.TSSObject;

type
  TSSString = class
  public
    class function SplitStringToArray(Str: string; const SplitFlag: Char): TStringDynArray; overload;
    class function SplitStringToList(Str: string; const SplitFlag: Char): TStringList; overload;
    class function VariantToString(Value: Variant): string;
  end;

  TSSStringListComponent = class(TSSObject)
  private
    _StringList: TStringList;
  public
    function GetStringList: TStringList;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

  ISSRecord = interface(ISSObject)
    ['{4B65517C-ABB9-4F9E-A06D-E167D4DF5A7C}']
    function GetBooleanValue(const AValueName: string): Boolean;
    function GetCurrencyValue(const AValueName: string): Currency;
    function GetDateTimeValue(const AValueName: string): TDateTime;
    function GetDoubleValue(const AValueName: string): Double;
    function GetIntegerValue(const AValueName: string): Integer;
    function GetStringValue(const AValueName: string): string;
    function GetValue(const AValueName: string): Variant;
    function GetValueCount: Integer;
    function GetValueName(const AIndex: Integer): string;
    procedure AppendValue(const AValueName: string; AValue: Variant);
  end;

  TSSVariantObject = class(TSSObject)
  public
    Value: Variant;
  end;

  TSSRecord = class(TSSObject, ISSRecord)
  private
    _ObjectContainer: ISSObjectContainer;
  public
    function GetBooleanValue(const AValueName: string): Boolean;
    function GetCurrencyValue(const AValueName: string): Currency;
    function GetDateTimeValue(const AValueName: string): TDateTime;
    function GetDoubleValue(const AValueName: string): Double;
    function GetIntegerValue(const AValueName: string): Integer;
    function GetStringValue(const AValueName: string): string;
    function GetValue(const AValueName: string): Variant;
    function GetValueCount: Integer;
    function GetValueName(const AIndex: Integer): string;
    procedure AppendValue(const AValueName: string; AValue: Variant);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

uses Variants,
  SysUtils,
  SmallStruct.Core.TSSObjectContainer;

{ TSSString }

class function TSSString.SplitStringToArray(Str: string; const SplitFlag: Char): TStringDynArray;
var
  I, J, L: Integer;

  procedure AppendBuffer(const SplitStr: string);
  begin
    SetLength(Result, Length(Result) + 1);
    Result[High(Result)] := SplitStr;
  end;

begin
  Str := Trim(Str);
  SetLength(Result, 0);

  I := 1;
  J := 1;
  L := Length(Str);

  while J <= L do
  begin
    if Str[I] = SplitFlag then
      Inc(I);

    if (J = Length(Str)) and (Str[J] <> ',') and ((J - I) > 0) then
    begin
      AppendBuffer(Trim(Copy(Str, I, J - I + 1)));
      I := J + 1;
    end
    else if (Str[J] = SplitFlag) and ((J - I) > 0) then
    begin
      AppendBuffer(Trim(Copy(Str, I, J - I)));
      I := J + 1;
    end;

    Inc(J);
  end;
end;

class function TSSString.SplitStringToList(Str: string; const SplitFlag: Char): TStringList;
var
  I, J, L: Integer;
begin
  Str := Trim(Str);
  Result := TStringList.Create;

  I := 1;
  J := 1;
  L := Length(Str);

  while J <= L do
  begin
    if Str[I] = SplitFlag then
      Inc(I);

    if (J = Length(Str)) and (Str[J] <> ',') and ((J - I) > 0) then
    begin
      Result.Add(Trim(Copy(Str, I, J - I + 1)));
      I := J + 1;
    end
    else if (Str[J] = SplitFlag) and ((J - I) > 0) then
    begin
      Result.Add(Trim(Copy(Str, I, J - I)));
      I := J + 1;
    end;

    Inc(J);
  end;
end;

class function TSSString.VariantToString(Value: Variant): string;
begin
  case VarType(Value) of
    varSmallInt,
      varInteger,
      varSingle,
      varShortInt,
      varWord,
      varLongWord,
      varInt64:
      Result := IntToStr(Value);
    varDouble,
      varCurrency:
      CurrToStr(Value);
    varString:
      Result := '''' + Value + '''';
  end;
end;

{ TSSStringListComponent }

constructor TSSStringListComponent.Create(AOwner: TComponent);
begin
  inherited;
  _StringList := TStringList.Create;
end;

destructor TSSStringListComponent.Destroy;
begin
  _StringList.Free;
  inherited;
end;

function TSSStringListComponent.GetStringList: TStringList;
begin
  Result := _StringList;
end;

{ TSSRecord }

procedure TSSRecord.AppendValue(const AValueName: string; AValue: Variant);
var
  VariantObject: TSSVariantObject;
begin
  VariantObject := TSSVariantObject.Create(nil);
  VariantObject.Value := AValue;
  try
    _ObjectContainer.AppendObject(AValueName, VariantObject);
  except
    on E: Exception do
    begin
      if _ObjectContainer.FindObject(AValueName) >= 0 then
        _ObjectContainer.RemoveObject(_ObjectContainer.FindObject(AValueName));
      VariantObject.Free;
      raise;
    end;
  end;
end;

constructor TSSRecord.Create(AOwner: TComponent);
begin
  inherited;
  _ObjectContainer := TSSObjectContainer.Create(nil);
end;

destructor TSSRecord.Destroy;
begin
  _ObjectContainer.ReleaseObject;
  _ObjectContainer.ReleaseObjectInstance;
  inherited;
end;

function TSSRecord.GetBooleanValue(const AValueName: string): Boolean;
begin
  Result := (_ObjectContainer.GetObject(AValueName) as TSSVariantObject).Value;
end;

function TSSRecord.GetCurrencyValue(const AValueName: string): Currency;
begin
  Result := (_ObjectContainer.GetObject(AValueName) as TSSVariantObject).Value;
end;

function TSSRecord.GetDateTimeValue(const AValueName: string): TDateTime;
begin
  Result := (_ObjectContainer.GetObject(AValueName) as TSSVariantObject).Value;
end;

function TSSRecord.GetDoubleValue(const AValueName: string): Double;
begin
  Result := (_ObjectContainer.GetObject(AValueName) as TSSVariantObject).Value;
end;

function TSSRecord.GetIntegerValue(const AValueName: string): Integer;
begin
  Result := (_ObjectContainer.GetObject(AValueName) as TSSVariantObject).Value;
end;

function TSSRecord.GetStringValue(const AValueName: string): string;
begin
  Result := (_ObjectContainer.GetObject(AValueName) as TSSVariantObject).Value;
end;

function TSSRecord.GetValue(const AValueName: string): Variant;
begin
  Result := (_ObjectContainer.GetObject(AValueName) as TSSVariantObject).Value;
end;

function TSSRecord.GetValueCount: Integer;
begin
  Result := _ObjectContainer.GetCount;
end;

function TSSRecord.GetValueName(const AIndex: Integer): string;
begin
  Result := _ObjectContainer.GetObjectName(AIndex);
end;

end.
